package com.cxx.home.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cxx.home.dto.food.*;
import com.cxx.home.mapper.FoodMaterialMapper;
import com.cxx.home.mapper.FoodStepMapper;
import com.cxx.home.mapper.FoodRecipeMapper;
import com.cxx.home.mapper.FoodRecordMapper;
import com.cxx.framework.web.CustomException;
import com.cxx.home.dao.FoodDao;
import com.cxx.home.entity.FoodMaterial;
import com.cxx.home.entity.FoodRecipe;
import com.cxx.home.entity.FoodRecord;
import com.cxx.home.entity.FoodStep;
import com.cxx.home.service.FoodService;
import com.cxx.home.vo.FoodQueryVo;
import com.github.yitter.idgen.YitIdHelper;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
public class FoodServiceImpl implements FoodService {
    @Resource
    private FoodDao foodDao;

    @Resource
    private FoodRecipeMapper foodRecipeMapper;

    @Resource
    private FoodMaterialMapper foodMaterialMapper;

    @Resource
    private FoodStepMapper foodStepMapper;

    @Resource
    private FoodRecordMapper foodRecordMapper;

    @Override
    @Transactional
    public Boolean addFoodRecipe(FoodRecipeDto foodRecipeDto) {
        LambdaQueryWrapper<FoodRecipe> queryWrapper = new LambdaQueryWrapper<>();
        if (foodRecipeMapper.exists(queryWrapper.eq(FoodRecipe::getName, foodRecipeDto.getName()))) {
            throw new CustomException("该菜谱已经存在");
        }

        FoodRecipe foodRecipe = new FoodRecipe();
        BeanUtils.copyProperties(foodRecipeDto, foodRecipe);
        foodRecipeMapper.insert(foodRecipe);
        resetFoodRecipe(foodRecipe.getId(), foodRecipeDto);

        return Boolean.TRUE;
    }

    @Override
    @Transactional
    public Boolean updateFoodRecipe(Long id, FoodRecipeDto foodRecipeDto) {
        if (foodRecipeMapper.selectById(id) == null) {
            throw new CustomException("该菜谱不存在");
        }

        FoodRecipe foodRecipe = new FoodRecipe();
        BeanUtils.copyProperties(foodRecipeDto, foodRecipe);
        foodRecipe.setId(id);
        foodRecipeMapper.updateById(foodRecipe);
        resetFoodRecipe(foodRecipe.getId(), foodRecipeDto);

        return Boolean.TRUE;
    }

    @Override
    @Transactional
    public Boolean deleteFoodRecipe(Long id) {
        foodRecipeMapper.deleteById(id);
        foodMaterialMapper.delete(Wrappers.lambdaQuery(FoodMaterial.class).eq(FoodMaterial::getFoodId, id));
        foodStepMapper.delete(Wrappers.lambdaQuery(FoodStep.class).eq(FoodStep::getFoodId, id));
        foodRecordMapper.delete(Wrappers.lambdaQuery(FoodRecord.class).eq(FoodRecord::getFoodId, id));

        return Boolean.TRUE;
    }

    @Override
    public Boolean addFoodRecord(FoodRecordDto foodRecordDto) {
        LambdaQueryWrapper<FoodRecipe> queryWrapper = new LambdaQueryWrapper<>();
        FoodRecipe foodRecipe = foodRecipeMapper.selectOne(queryWrapper.eq(FoodRecipe::getName, foodRecordDto.getName()));
        if (foodRecipe == null) {
            throw new CustomException("该菜谱不存在");
        }

        FoodRecord foodRecord = new FoodRecord();
        foodRecord.setFoodId(foodRecipe.getId());
        BeanUtils.copyProperties(foodRecordDto, foodRecord);
        foodRecordMapper.insert(foodRecord);

        return Boolean.TRUE;
    }

    @Override
    public Boolean updateFoodRecord(Long id, FoodRecordDto foodRecordDto) {
        if (foodRecordMapper.selectById(id) == null) {
            throw new CustomException("该成果不存在");
        }

        FoodRecord foodRecord = new FoodRecord();
        BeanUtils.copyProperties(foodRecordDto, foodRecord);
        foodRecord.setId(id);
        foodRecordMapper.updateById(foodRecord);

        return Boolean.TRUE;
    }

    @Override
    public Boolean deleteFoodRecord(Long id) {
        foodRecordMapper.deleteById(id);

        return Boolean.TRUE;
    }

    private void resetFoodRecipe(Long id, FoodRecipeDto foodRecipeDto) {
        foodMaterialMapper.delete(Wrappers.lambdaQuery(FoodMaterial.class).eq(FoodMaterial::getFoodId, id));
        foodStepMapper.delete(Wrappers.lambdaQuery(FoodStep.class).eq(FoodStep::getFoodId, id));

        insertFoodMaterial(id, foodRecipeDto.getMaterialList());
        insertFoodStep(id, foodRecipeDto.getStepList());
    }

    private void insertFoodMaterial(Long foodId, List<FoodMaterialDto> foodMaterialList) {
        if (foodMaterialList.isEmpty()) {
            return;
        }

        foodMaterialList.forEach((item) -> {
            item.setId(YitIdHelper.nextId());
        });
        foodDao.insertFoodMaterial(foodId, foodMaterialList);
    }

    private void insertFoodStep(Long foodId, List<FoodStepDto> foodStepList) {
        if (foodStepList.isEmpty()) {
            return;
        }

        foodStepList.forEach((item) -> {
            item.setId(YitIdHelper.nextId());
        });
        foodDao.insertFoodStep(foodId, foodStepList);
    }

    @Override
    public FoodRecipeDto queryFoodRecipe(Long id) {
        if (foodRecipeMapper.selectById(id) == null) {
            throw new CustomException("该美食不存在");
        }

        return foodDao.queryFoodRecipe(id);
    }

    @Override
    public IPage<FoodSummaryDto> queryFoodSummary(Integer currentPage, Integer pageSize, FoodQueryVo foodQueryVo) {
        // 这里只能先对主表进行分页 然后在查询子表信息
        // 不能使用Left Join关联表查询，因为这里是一对多数据，关联查询会导致数据有重复
        // 从而导致page计算错误（会把重复的数据当成多条记录，实际上只有1条记录）
        IPage<FoodSummaryDto> foodSummaryPage = foodDao.queryFoodSummary(new Page<>(currentPage, pageSize), foodQueryVo);
        List<FoodSummaryDto> foodSummaryList = foodSummaryPage.getRecords();
        for (FoodSummaryDto foodSummary : foodSummaryList) {
            foodSummary.setRecordList(foodDao.queryFoodRecordById(foodSummary.getId()));
        }

        foodSummaryPage.setRecords(foodSummaryList);
        return foodSummaryPage;
    }

    @Override
    public List<FoodRecordDto> queryFoodRecord(String startDate, String endDate) {
        return foodDao.queryFoodRecord(startDate, endDate);
    }

    @Override
    public List<String> queryFoodName() {
        return foodRecipeMapper.selectList(null)
                .stream().map(FoodRecipe::getName).collect(Collectors.toList());
    }

    @Override
    public List<String> queryFoodCategory() {
        return foodDao.queryFoodCategory();
    }

    @Override
    public FoodStatsDto queryFoodStats() {
        return foodDao.queryFoodStats();
    }
}
